package com.study.studyelasticsearch.client.highLevelClient;

import com.alibaba.fastjson.JSON;
import com.study.studyelasticsearch.client.EsAnalyzer;
import com.study.studyelasticsearch.client.EsDoc;
import com.study.studyelasticsearch.client.EsIndex;
import com.study.studyelasticsearch.client.EsQuery;
import com.study.studyelasticsearch.util.es.curd.vo.AnalyzeVo;
import com.study.studyelasticsearch.util.es.curd.vo.DeleteDocVo;
import org.elasticsearch.ResourceAlreadyExistsException;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.*;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.elasticsearch.index.reindex.UpdateByQueryRequest;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * ES 如何打印日志：http://www.proyy.com/6994756760363859999.html
 * 封装了常用的ES方法
 * @author 吴宇亮 on 2022/7/28 20:43
 */
@Component
public class RestHighEsClient implements EsIndex, EsAnalyzer, EsDoc, EsQuery {

    @Autowired
    @Qualifier("elasticsearchClient")
    private RestHighLevelClient client;

    @Override
    public String[] listIndexs() {
        return this.listIndexs("*");
    }

    @Override
    public String[] listIndexs(String indexName, boolean isExact) {
        try {
            if(!isExact) {
                indexName = "*" + indexName + "*";
            }
            GetIndexResponse getIndexResponse = client.indices().get(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
            return getIndexResponse.getIndices();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#listIndexs错误");
        }
    }

    @Override
    public String[] listIndexs(String indexName) {
        return this.listIndexs(indexName, false);
    }

    @Override
    public boolean indexExist(String indexName, boolean isExact) {
        try {
            if(!isExact){
                indexName = "*" + indexName + "*";
            }
            return client.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#indexExist错误");
        }
    }

    @Override
    public boolean indexExist(String indexName) {
        return this.indexExist(indexName, false);
    }

    @Override
    public boolean createIndex(String indexName) throws ResourceAlreadyExistsException {
        try {
            CreateIndexResponse response = client.indices().create(new CreateIndexRequest(indexName), RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#createIndex错误");
        }
    }

    @Override
    public boolean createIndex(String indexName, EsAnalyzer.Analyzer analyzer) {
        try {
            CreateIndexRequest request = new CreateIndexRequest(indexName);
            request.settings(Settings.builder()
                    .put(EsIndex.Config.ANALYZER_TYPE, analyzer.name())
            );
            CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#createIndex错误");
        }
    }

    @Override
    public boolean deleteIndex(Collection<String> indexNames) {
        for (String indexName : indexNames) {
            this.deleteIndex(indexName);
        }
        return true;
    }

    @Override
    public boolean deleteIndex(String... indexNames) throws IndexNotFoundException {
        try {
            DeleteIndexRequest request = new DeleteIndexRequest("posts");
            AcknowledgedResponse deleteIndexResponse = client.indices().delete(request, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#deleteIndex错误");
        }
    }

    @Override
    public boolean deleteIndexIfExist(String... indexNames) {
        for (String indexName : indexNames) {
            if (this.indexExist(indexName, true)) {
                this.deleteIndex(indexName);
            }
        }
        return true;
    }

    @Override
    public List<AnalyzeVo> analyze(Analyzer analyzer, String text) {
        try {
            AnalyzeRequest request = AnalyzeRequest.withGlobalAnalyzer(analyzer.name(), text);
            AnalyzeResponse response = client.indices().analyze(request, RequestOptions.DEFAULT);

            List<AnalyzeVo> result = new ArrayList<>(response.getTokens().size());
            for (AnalyzeResponse.AnalyzeToken token : response.getTokens()) {
                AnalyzeVo vo = new AnalyzeVo();
                vo.setText(token.getTerm());
                vo.setType(token.getType());
                result.add(vo);
            }
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#analyze错误");
        }
    }

    @Override
    public <T> void saveOrUpdateDoc(String indexName, T doc, String docId) {
        UpdateRequest request = new UpdateRequest(indexName, docId);
        request.doc(JSON.toJSONString(doc), XContentType.JSON);
        try {
            UpdateResponse updateResponse = client.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#saveOrUpdateDoc错误");
        }
    }

    @Override
    public List<DeleteDocVo> deleteDoc(String indexName, String... ids) {
        try {
            BulkRequest request = new BulkRequest();
            for (String id : ids) {
                request.add(new DeleteRequest(indexName, id));
            }
            BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#deleteDoc错误");
        }
        return null;
    }

    @Override
    public boolean deleteAllDoc(String indexName) {
        try {
            DeleteByQueryRequest request = new DeleteByQueryRequest(indexName);
            request.setQuery(new MatchAllQueryBuilder());
            BulkByScrollResponse bulkResponse = client.deleteByQuery(request, RequestOptions.DEFAULT);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#deleteAllDoc错误");
        }
    }

    @Override
    public void updateByQuery() {
        try {
            UpdateByQueryRequest request = new UpdateByQueryRequest("source1", "source2");
            request.setScript(new Script(ScriptType.INLINE, "painless", "if (ctx._source.user == 'kimchy') {ctx._source.likes++;}", Collections.emptyMap()));
            BulkByScrollResponse bulkResponse = client.updateByQuery(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("RestHighEsClient#updateByQuery错误");
        }
    }

    @Override
    public void query(QueryBuilder queryBuilder) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy"));
        sourceBuilder.from(0);
        sourceBuilder.size(5);
    }

    // ES集合预算？

//    ES做交集
//    https://blog.csdn.net/Lakers_KobeBryant/article/details/79052193
}
